<?php
/**
 *
 * @author 凡墙<jihaoju@qq.com>
 * @date 2018/7/13 10:41
 * @description
 */

namespace apps\marriage\core\logic;

use think\Exception;
use think\facade\Log;
use apps\marriage\core\service\CacheService;
use vm\com\BaseService;
use vm\org\HttpUtil;
use vm\org\weixin\WXBizMsgCrypt;

class WxMiniLogic
{
    protected $appid = '';
    protected $appSecret = '';
    protected $token = '';
    protected $EncodingAESKey = '';

    const WX_MINI_USER_SESSION_CACHE_PREFIX = 'wx_mini_user_session:';
    const WX_MINI_QRCODE_SCENE_PREFIX = 'wx_mini_qrcode_scene:';
    const SHARE_FROM_QRCODE = 'qrcode';
    const DIALOG_CACHE_PREFIX = 'weapp_dialog:';

    /**
     * @var BaseService|CacheService
     */
    protected $cacheService;

    private $httpUtil = null;

    public function __construct()
    {
        $this->cacheService = service('Cache', SERVICE_NAMESPACE);
        $this->httpUtil = new HttpUtil();
    }

    public function getAppid()
    {
        return $this->appid;
    }

    public function setAppid($appId)
    {
        $weapp = config('weapp');
        $cfg = $weapp[$appId];
        $this->appid = $appId;
        $this->appSecret = $cfg['app_secret'];
        $this->token = $cfg['token'];
        $this->EncodingAESKey = $cfg['EncodingAESKey'];
    }

    public function getAppSecret()
    {
        return $this->appSecret;
    }

    protected function get($url)
    {
        $result = $this->httpUtil->curl($url, HttpUtil::REQUEST_METHOD_GET);
        $ret = json_decode($result, TRUE);
        if (isset($ret['errmsg']) && $ret['errcode'] != 0) {
            Log::error('请求微信接口出错，errcode:' . $ret['errcode'] . ',errmsg:' . $ret['errmsg']);
            throw new Exception($ret['errmsg']);
        }
        return $ret;
    }

    protected function post($url, $data)
    {
        $result = $this->httpUtil->curl($url, HttpUtil::REQUEST_METHOD_POST, $data);
        $ret = json_decode($result, TRUE);
        if (isset($ret['errmsg']) && $ret['errcode'] != 0) {
            Log::error('请求微信接口出错，errcode:' . $ret['errcode'] . ',errmsg:' . $ret['errmsg']);
            throw new Exception($ret['errmsg']);
        }
        return $ret;
    }

    /**
     * 发起请求
     * @param string $url 请求地址
     * @param string $data 请求数据包
     * @return   string      请求返回数据
     * @throws
     */
    public function sendCmd($url, $data)
    {
        $curl = curl_init(); // 启动一个CURL会话
        curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检测
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); // 从证书中检查SSL加密算法是否存在
        curl_setopt($curl, CURLOPT_HTTPHEADER, array('Expect:')); //解决数据包大不能提交
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
        curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
        curl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data); // Post提交的数据包
        curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循
        curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回

        $tmpInfo = curl_exec($curl); // 执行操作
        if (curl_errno($curl)) {
            $Errno = curl_error($curl);
            curl_close($curl);
            throw new Exception($Errno);
        }
        curl_close($curl); // 关键CURL会话
        return $tmpInfo; // 返回数据
    }

    public function getAccessToken()
    {
        $cacheName = 'wx_miniapp_access_token_' . $this->appid;
        $data = $this->cacheService->get($cacheName);
        if ($data) {
            return $data;
        }
        $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $this->appid . '&secret=' . $this->appSecret;
        $ret = $this->get($url);
        $accessToken = $ret['access_token'];
        $expiresIn = $ret['expires_in'];
        $this->cacheService->set($cacheName, $accessToken, time() + $expiresIn - 60);
        return $accessToken;
    }

    public function getOpenIdByCode($code)
    {
        $url = 'https://api.weixin.qq.com/sns/jscode2session?appid=' . $this->appid . '&secret=' . $this->appSecret . '&js_code=' . $code . '&grant_type=authorization_code';
        $ret = $this->get($url);
        return $ret;
    }

    /**
     * 生成小程序码
     * @param $scene
     * @param $path
     * @return 数据流
     * @throws Exception
     */
    public function genWxMiniQrcode($scene, $path)
    {
        $url = 'https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=' . $this->getAccessToken();
        $data = [
            'scene' => $scene,
            'page' => $path,
            'width' => 430,
            'is_hyaline' => false
        ];
        $result = $this->sendCmd($url, json_encode($data));
        if (stripos($result, 'errcode') !== false && stripos($result, 'errmsg') !== false) {
            $result = json_decode($result, true);
            throw new Exception('errcode:' . $result['errcode'] . ',errmsg:' . $result['errmsg']);
        }
        return $result;
    }

    public function genScene($path, $isTab, $params = [])
    {
        $scene = md5($path . rand_string(30) . time());
        $data = [
            'path' => $path,
            'is_tab' => $isTab,
            'params' => $params
        ];
        $this->cacheService->set(self::WX_MINI_QRCODE_SCENE_PREFIX . $scene, $data, 0);
        return $scene;
    }

    public function decodeScene($scene)
    {
        return $this->cacheService->get(self::WX_MINI_QRCODE_SCENE_PREFIX . $scene);
    }

    public function checkSignature($signature, $nonce, $timestamp)
    {
        $tmpArr = array($this->token, $timestamp, $nonce);
        sort($tmpArr, SORT_STRING);
        $tmpStr = implode($tmpArr);
        $tmpStr = sha1($tmpStr);

        if ($tmpStr == $signature) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 消息或事件通知
     * @param $authorizerAppid
     * @param $timestamp
     * @param $nonce
     * @param $encryptType
     * @param $msgSignature
     * @param array $postData
     * @return string
     * @throws Exception
     */
    public function receiveMsgFeed(array $postData, $timestamp, $nonce, $encryptType, $msgSignature)
    {
        $WXBizMsgCrypt = new WXBizMsgCrypt($this->token, $this->EncodingAESKey, $this->appid);
        $msg = '';
        $WXBizMsgCrypt->decryptData($msgSignature, $timestamp, $nonce, $postData['Encrypt'], $msg);
        $msg = xmlToArray($msg);
        return $msg;
    }

    public function sendCustomServiceMessage(array $mesage)
    {
        $url = 'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=' . $this->getAccessToken();
        $result = $this->sendCmd($url, json_encode($mesage, JSON_UNESCAPED_UNICODE));
        $result = json_decode($result, true);
        if($result['errcode'] != 0) {
            Log::error('errcode:' . $result['errcode'] . ',errmsg:' . $result['errmsg']);
            throw new Exception($result['errmsg']);
        }
        return true;
    }

    public function submitPages(array $pages)
    {
        $url = 'https://api.weixin.qq.com/wxa/search/wxaapi_submitpages?access_token=' . $this->getAccessToken();
        $result = $this->sendCmd($url, json_encode(['pages' => $pages], JSON_UNESCAPED_UNICODE));
        $result = json_decode($result, true);
        if($result['errcode'] != 0) {
            Log::error('errcode:' . $result['errcode'] . ',errmsg:' . $result['errmsg']);
//            throw new Exception($result['errmsg']);
        }
        return true;
    }
}